home *** CD-ROM | disk | FTP | other *** search
- // -------------------------------------------------------------------------------------
- // ImagePortfolio.m - Visual TIFF/EPS file manager
- // -------------------------------------------------------------------------------------
- // Permission is granted to freely redistribute this source code, and to use fragments
- // of this code in your own applications if you find them to be useful. This class,
- // along with the source code, come with no warranty of any kind, and the user assumes
- // all responsibility for its use.
- // -------------------------------------------------------------------------------------
-
- extern "Objective-C" {
- #import <objc/objc.h>
- #import <appkit/appkit.h>
- #import <libc.h>
- #import <stdlib.h>
- #import <stdio.h>
- #import <string.h>
- #import <mach/mach.h>
- #import <defaults/defaults.h>
- #import <dpsclient/wraps.h>
- #import <3Dkit/N3DRIBImageRep.h>
- #import "appUtils.h"
- #import "fileUtils.h"
- #import "ScrollText.h"
- }
-
- #import "GifImageRep.h"
- #import "ImagePortfolio.h"
- #import "Portfolio.h"
- #import "PaletteCell.h" // for adding support image types
- #import "PaletteMatrix.h"
-
- // -------------------------------------------------------------------------------------
- // application version string
- extern "C" { extern char *appVersion; }
-
- // -------------------------------------------------------------------------------------
- // HELP file name (in language directory)
- #define HELP_FILE "HELP.rtfd"
-
- // -------------------------------------------------------------------------------------
- // preferences
- static BOOL prefUseNXImageClass = YES;
-
- // -------------------------------------------------------------------------------------
- // NXImages
- static id dockIcon = (id)nil;
- static id openFolder = (id)nil;
-
- // -------------------------------------------------------------------------------------
- // PasteBoard dragging operation variables
- // Note: Only one drag operation can occur at any given time.
- BOOL pbDragFilesOk = NO;
- NXAtom pbTypes[] = { NXFilenamePboardType };
- int pbNumTypes = 1;
- int pbChangeCount = 0;
-
- // -------------------------------------------------------------------------------------
- // This is done for the purpose of allowing to setDelegate on the appIcon window
- // [DelegateWindow poseAs:[Window class]] must be issued in +new(Application)
- @interface DelegateWindow:Window @end
- @implementation DelegateWindow
- - setDelegate:sender
- {
- if ((wFlags.style != NX_TOKENSTYLE) && (wFlags.style != NX_MINIWORLDSTYLE)) {
- [super setDelegate:sender];
- } else {
- int saveStyle = wFlags.style;
- wFlags.style = NX_PLAINSTYLE;
- [super setDelegate:sender];
- wFlags.style = saveStyle;
- }
- return self;
- }
- @end
-
- // -------------------------------------------------------------------------------------
- @implementation ImagePortfolio
-
- // -------------------------------------------------------------------------------------
- // menu/button actions
-
- /* make and show new image Palette */
- - newImagePalette:sender
- {
- return [[Portfolio alloc] initFromList:(ParseString*)nil];
- }
-
- /* open Palette file */
- - open:sender
- {
- id pOpen;
- char fName[MAXPATHLEN+1], *dir, **files, *fTypes[] = { docEXTENSION, 0 };
-
- /* build/display open panel */
- pOpen = [OpenPanel new];
- [pOpen setTitle:"Open Image Portfolio"];
- [pOpen setPrompt:"File:"];
- [pOpen setRequiredFileType:fTypes[0]];
- [pOpen allowMultipleFiles:YES];
- [pOpen setDirectory:[NXApp lastPath]];
- if (![pOpen runModalForTypes:fTypes]) return self;
-
- /* open the list of selected files */
- if (!(files = (char**)[pOpen filenames])) return self;
- if (dir=(char*)[pOpen directory]) { chdir(dir); [self setLastPath:dir]; }
- while (*files) {
- sprintf(fName, "%s/%s", dir, *files++);
- ParseString fileNames = fName;
- [[Portfolio alloc] initFromList:&fileNames];
- }
-
- return self;
- }
-
- /* arrange windows in front */
- - arrangeInFront:sender
- {
- return self;
- }
-
- /* show info panel */
- - showInfo:sender
- {
- if (!infoIsLoaded) {
- [infoPanel center];
- infoIsLoaded = YES;
- }
- return [infoPanel makeKeyAndOrderFront:sender];
- }
-
- /* show help panel */
- - showHelp:sender
- {
- if (!helpIsLoaded) {
- char path[MAXPATHLEN + 1];
- NXBundle *mBundle = [NXBundle mainBundle];
- BOOL found = [mBundle getPath:path forResource:HELP_FILE ofType:(char*)nil];
- if (!found) { NXBeep(); return self; }
- [[helpScroll docView] openRTFDFrom:path];
- [helpPanel center];
- helpIsLoaded = YES;
- }
- return [helpPanel makeKeyAndOrderFront:sender];
- }
-
- /* show preferences panel (to be called by PaletteMatrix only!) */
- - showPreferences:sender
- {
- id winDel = [Portfolio activePortfolio];
- int rows, cols;
-
- /* exit if not proper portfolio type (must match sender) */
- if (!winDel || ![winDel isKindOf:[Portfolio class]]) return self;
-
- /* set screen fields */
- [fontName setStringValue:[[winDel font] name]];
- [fontSize setFloatValue:[[winDel font] pointSize]];
- [prefCellWidth setFloatValue:[winDel cellSize]->width ];
- [prefCellHeight setFloatValue:[winDel cellSize]->height];
- [winDel getDisplayedRows:&rows cols:&cols];
- [prefCellRows setIntValue:rows];
- [prefCellColumns setIntValue:cols];
-
- /* pref panel init */
- if (!prefIsLoaded) {
- [prefPanel center];
- prefIsLoaded = YES;
- }
-
- /* show window */
- [prefPanel makeKeyAndOrderFront:sender];
- [NXApp runModalFor:prefPanel];
-
- return self;
- }
-
- /* cancel preferences */
- - cancelPreferences:sender
- {
- [NXApp stopModal:0];
- [prefPanel orderOut:sender];
- return self;
- }
-
- /* save preference to defaults table */
- - saveDefaults:sender
- {
- id winDel = [Portfolio activePortfolio];
- if (winDel && [winDel isKindOf:[Portfolio class]]) [winDel saveDefaults:sender];
- return self;
- }
-
- /* print key window */
- - printKeyWindow:sender
- {
- return (keyWindow)? [keyWindow smartPrintPSCode:sender] : (id)nil;
- }
-
- // -------------------------------------------------------------------------------------
- // return application constants
-
- /* set last default saved/openned file path */
- - setLastPath:(char*)path
- {
- if (lastPath) free(lastPath);
- lastPath = NXCopyStringBuffer(path);
- return self;
- }
-
- /* return last saved/openned path */
- - (const char*)lastPath
- {
- return (lastPath)? lastPath : NXHomeDirectory();
- }
-
- // -------------------------------------------------------------------------------------
- // inline event dispatcher
- // - When this method is interleaved with other methods, such as loading a large image
- // directory, this allows continued interaction with the user.
- - dispatchEvents
- {
- NXEvent *e;
- while (e=[NXApp getNextEvent:NX_MOUSEDOWNMASK waitFor:0.0 threshold:NX_BASETHRESHOLD])
- [NXApp sendEvent:e];
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // menu cell update handler methods
-
- - _setMenuCellsUpdateAction:menuId
- {
- id cellList = [[menuId itemList] cellList];
- int i = [cellList count];
- while(i) {
- id cell = [cellList objectAt:--i];
- SEL updAct, cSel = [cell action];
- if ([cell hasSubmenu]) { [self _setMenuCellsUpdateAction:[cell target]]; continue; }
- if ([cell target]) continue;
- updAct = @selector(_ucKeyWindow:); // default updateAction
- if (cSel==@selector(cut:) ) updAct=@selector(_ucCutCopyDelete:); else
- if (cSel==@selector(copy:) ) updAct=@selector(_ucCutCopyDelete:); else
- if (cSel==@selector(delete:) ) updAct=@selector(_ucCutCopyDelete:); else
- if (cSel==@selector(undelete:) ) updAct=@selector(_ucUndelete:); else
- if (cSel==@selector(paste:) ) updAct=@selector(_ucResponder:); else
- if (cSel==@selector(save:) ) updAct=@selector(_ucSelectable:); else
- if (cSel==@selector(saveAs:) ) updAct=@selector(_ucSelectable:); else
- if (cSel==@selector(print:) ) updAct=@selector(_ucSelectable:); else
- if (cSel==@selector(selectAll:) ) updAct=@selector(_ucSelectable:); else
- if (cSel==@selector(sortByCellTitle:) ) updAct=@selector(_ucSelectable:); else
- if (cSel==@selector(showPreferences:) ) updAct=@selector(_ucMainWindow:); else
- if (cSel==@selector(performClose:) ) updAct=@selector(_ucKeyWindow:); else
- if (cSel==@selector(performMiniaturize:)) updAct=@selector(_ucKeyWindow:); else
- if (cSel==@selector(printKeyWindow:) ) updAct=@selector(_ucKeyWindow:);
- [cell setUpdateAction:updAct forMenu:menuId];
- [menuId setAutoupdate:YES];
- }
- return self;
- }
-
- /* return menuCell responder */
- - _cellResponder:cellId
- {
- id respId = (keyWindow)? [keyWindow firstResponder] : (id)nil;
- return (respId && [respId respondsTo:[cellId action]])? respId : (id)nil;
- }
-
- /* return menuCell enabling flag */
- - (BOOL)_cellEnabler:cellId :(SEL)meth
- {
- id respId = [self _cellResponder:cellId];
- [cellId setEnabled:((respId&&[respId respondsTo:meth]&&[respId perform:meth])?YES:NO)];
- return YES;
- }
-
- /* print/save/saveAs/selectAll: cells selectable */
- - (BOOL)_ucSelectable:cellId
- {
- return [self _cellEnabler:cellId :@selector(anySelectableCells)];
- }
-
- /* cut/copy/delete */
- - (BOOL)_ucCutCopyDelete:cellId
- {
- return [self _cellEnabler:cellId :@selector(selectedCell)];
- }
-
- /* undelete */
- - (BOOL)_ucUndelete:cellId
- {
- return [self _cellEnabler:cellId :@selector(undeletable)];
- }
-
- /* keyWindow menu cell update method */
- - (BOOL)_ucKeyWindow:cellId
- {
- [cellId setEnabled:(keyWindow?YES:NO)];
- return YES;
- }
-
- /* mainWindow menu cell update method */
- - (BOOL)_ucMainWindow:cellId
- {
- [cellId setEnabled:(mainWindow?YES:NO)];
- return YES;
- }
-
- /* paste */
- - (BOOL)_ucResponder:cellId
- {
- [cellId setEnabled:([self _cellResponder:cellId]?YES:NO)];
- return YES;
- }
-
- // -------------------------------------------------------------------------------------
- // application delegate
-
- /* Application instantiation */
- + new
- {
- [DelegateWindow poseAs:[Window class]];
- return [super new];
- }
-
- /* application initialization */
- - appDidInit:sender
- {
- int globalWinNum;
-
- /* clear vars */
- lastPath = (char*)nil;
- helpIsLoaded = NO;
- infoIsLoaded = NO;
- prefIsLoaded = NO;
-
- /* cache app path */
- XAppPath();
-
- /* load constant NXImages */
- if (!dockIcon) dockIcon = [NXImage findImageNamed:"app"];
- if (!openFolder) openFolder = [NXImage findImageNamed:"openFolder"];
-
- /* set the first responder update actions */
- [self setAutoupdate:YES];
- [self _setMenuCellsUpdateAction:[NXApp mainMenu]];
-
- /* set version number */
- [versionNum setStringValue:appVersion];
-
- /* add supported image file types */
- // these file extensions are checked for quick image qualification since many non-image
- // files may pass through a Portfolio window. A preference should be able to be set
- // that allows using NXImage as a catch-all when these fail. 'prefUseNXImageClass' is
- // currently hardcoded in this module.
- [PaletteCell addImageClass:[GifImageRep class]];
- [PaletteCell addImageExtensions:".gif", (char*)nil];
- if (prefUseNXImageClass) {
- [PaletteCell addImageClass:[NXImage class]];
- [PaletteCell addImageExtensions:"*"];
- } else {
- [PaletteCell addImageClass:[NXBitmapImageRep class]];
- [PaletteCell addImageClass:[NXEPSImageRep class]];
- [PaletteCell addImageClass:[N3DRIBImageRep class]];
- [PaletteCell addImageExtensions:".tiff",".tif",".icon",(char*)nil];
- [PaletteCell addImageExtensions:".eps",".ps",".ai",(char*)nil];
- [PaletteCell addImageExtensions:".rib",(char*)nil];
- }
-
- /* make app active */
- [NXApp activateSelf:YES];
-
- /* find real appIcon local window number and register for dragging */
- [[NXApp appIcon] setDelegate:self];
- NXConvertWinNumToGlobal([[NXApp appIcon] windowNum], (u_int*)&globalWinNum);
- NXConvertGlobalToWinNum(globalWinNum, (u_int*)&appIconWinNum);
- [[NXApp appIcon] registerForDraggedTypes:pbTypes count:pbNumTypes];
-
- return self;
- }
-
- /* application termination (check windows for unsaved files) */
- - appWillTerminate:sender
- {
-
- /* display panel if unsaved files are found */
- if ([Portfolio isDocEdited]) {
- int rtn;
- const char *msg, *quit, *qAny, *cncl;
- msg = NXLocalizedString("There are edited windows.", (char*)nil,(char*)nil);
- quit = NXLocalizedString("Quit", (char*)nil,(char*)nil);
- qAny = NXLocalizedString("Quit Anyway", (char*)nil,(char*)nil);
- cncl = NXLocalizedString("Cancel", (char*)nil,(char*)nil);
- rtn = NXRunAlertPanel(quit, msg, qAny, cncl, (char*)nil);
- if (rtn == NX_ALERTALTERNATE) return (id)nil;
- }
-
- /* MUST unregister appIcon window, otherwise drag may fail next time app is launched */
- [[NXApp appIcon] unregisterDraggedTypes];
-
- /* return */
- return self;
- }
-
- // -------------------------------------------------------------------------------------
- // Command-Shift file dragging
- static Portfolio *portfolioId = (id)nil;
-
- /* delayed clear porfolioId */
- - _clearPortfolioId:sender
- {
- portfolioId = (id)nil;
- return self;
- }
-
- /* open a Workspace Manager provided file */
- - (int)appOpenFile:(char*)filename type:(char*)type
- {
- BOOL isDoc = strcmp(XFileExtension(filename), dotDocEXTENSION)? NO : YES;
- ParseString imageFiles = filename;
-
- /* load file */
- if (isDoc) [[Portfolio alloc] initFromList:&imageFiles];
- else {
- if (!portfolioId) portfolioId = [[Portfolio alloc] initFromList:&imageFiles];
- else [portfolioId loadFileList:&imageFiles :NO :YES];
- }
-
- /* restart portfolioId clear */
- [self perform:@selector(_clearPortfolioId:) with:self
- afterDelay:2000 cancelPrevious:YES];
-
- return YES;
- }
-
- /* indicate to Workspace Manager that I accept files */
- - (BOOL)appAcceptsAnotherFile:sender { return YES; }
-
- // -------------------------------------------------------------------------------------
- // application icon window delegate
- // - This section handles files dragged and dropped onto the application icon
-
- /* set icon button image */
- - _setFileIcon:imageId
- {
- XSetAppIcon(imageId?imageId:dockIcon);
- return self;
- }
-
- /* files entered icon window */
- - (NXDragOperation)draggingEntered:sender
- {
- Pasteboard *pb = [sender draggingPasteboard];
- pbDragFilesOk = YES;
- if (![pb findAvailableTypeFrom:pbTypes num:pbNumTypes]) pbDragFilesOk = NO; else
- if (pbChangeCount == [pb changeCount]) pbDragFilesOk = NO;
- if (pbDragFilesOk) { [self _setFileIcon:openFolder]; return NX_DragOperationCopy; }
- return NX_DragOperationNone;
- }
-
- /* file icon moved to location */
- - (NXDragOperation)draggingUpdated:sender
- {
- return pbDragFilesOk? NX_DragOperationCopy : NX_DragOperationNone;
- }
-
- /* mouse exited icon window */
- - draggingExited:sender
- {
- [self _setFileIcon:(id)nil];
- pbDragFilesOk = NO;
- return self;
- }
-
- /* indicate we accept dragging */
- - (BOOL)prepareForDragOperation:sender
- {
- return pbDragFilesOk? YES : NO;
- }
-
- /* files dropped in icon window */
- - (BOOL)performDragOperation:sender
- {
- char *fileList;
- int fileListLen;
- Pasteboard *pb = [sender draggingPasteboard];
- [self _setFileIcon:(id)nil];
- if (pbDragFilesOk && [pb readType:pbTypes[0] data:&fileList length:&fileListLen]) {
- ParseString dragFiles = fileList;
- [pb deallocatePasteboardData:fileList length:fileListLen];
- pbChangeCount = [pb changeCount];
- pbDragFilesOk = NO;
- if (dragFiles[0]) {
- [NXApp activateSelf:YES];
- [[Portfolio alloc] initFromList:&dragFiles];
- return YES;
- }
- }
- return NO;
- }
-
- /* clean up */
- - concludeDragOperation:sender
- {
- return self;
- }
-
- /* find window for number (special case for appIcon window) */
- - findWindow:(int)windowNum
- {
- id winId = [super findWindow:windowNum];
- return (winId || (windowNum != appIconWinNum))? winId : [NXApp appIcon];
- }
-
- // -------------------------------------------------------------------------------------
- // outlet initialization
-
- - setHelpScroller:anObject
- {
- helpScroll = [[[ScrollText newScrollText:anObject] clearScrollText] setDelegate:self];
- textPrintf(helpScroll, "\n"); // this forces the scroll view to initialize
- [helpScroll clearScrollText];
- return self;
- }
-
- @end
-